package com.faner4cloud.yun.common.util;

import java.util.Collections;
import java.util.Objects;
import java.util.Set;
import java.util.function.Function;
import java.util.stream.Collectors;

import javax.annotation.Nonnull;

import org.springframework.util.StringUtils;

import com.google.common.base.Splitter;
import com.google.common.primitives.Longs;

/**
 * @author ...zz
 * @version v1
 * @summary 参数实用类
 * @since 2022/5/12 4:55 PM
 */
public final class ParamUtil {
	/**
	 * 英文逗号(,)分隔符
	 */
	public static final char DELIMITER_COMMA = ',';
	/**
	 * 英文冒号(:)分隔符
	 */
	public static final char DELIMITER_COLON = ':';

	/**
	 * 将参数值按照分隔符拆分，最后转换成{@link E}型Set返回。
	 *
	 * @param input     参数值
	 * @param sp        分割后的字符串处理器
	 * @param delimeter 分隔符，可参考常量{@link #DELIMITER_COMMA}
	 * @return 不会返回Null，如果不存在数据则返回emptySet
	 */
	public static @Nonnull <E> Set<E> splitToSet(CharSequence input, char delimeter, Function<String, E> sp) {
		if (StringUtils.isEmpty(input)) {
			return Collections.emptySet();
		}
		return Splitter.on(delimeter).omitEmptyStrings().trimResults().splitToList(input).stream()
			.map(sp).filter(Objects::nonNull).collect(Collectors.toSet());
	}

	/**
	 * 将参数值按照分隔符拆分，最后转换成{@link E}型Set返回。
	 * </p>
	 * 默认分隔符 {@link #DELIMITER_COMMA}
	 * </p>
	 *
	 * @param input 参数值
	 * @param sp    分割后的字符串处理器
	 * @return 不会返回Null，如果不存在数据则返回emptySet
	 * @see ParamUtil#splitToSet(CharSequence, char, Function)
	 */
	public static @Nonnull <E> Set<E> splitToSet(CharSequence input, Function<String, E> sp) {
		return splitToSet(input, DELIMITER_COMMA, sp);
	}

	/**
	 * 将参数值按照分隔符拆分，最后转换成Long型Set返回。
	 * </p>
	 * 注意：会将空字符串、无法转换为Long的字符串过滤掉，重复的参数会去重。
	 *
	 * @param input     参数值
	 * @param delimeter 分隔符，可参考常量{@link #DELIMITER_COMMA}
	 * @return 不会返回Null，如果不存在数据则返回emptySet
	 */
	public static @Nonnull Set<Long> splitToLongSet(CharSequence input, char delimeter) {
		return splitToSet(input, delimeter, (str) -> Longs.tryParse(str));
	}

	/**
	 * 将参数值按照分隔符拆分，最后转换成Long型Set返回。
	 * </p>
	 * 默认分隔符 {@link #DELIMITER_COMMA}
	 * </p>
	 * 注意：会将空字符串、无法转换为Long的字符串过滤掉，重复的参数会去重。
	 * </p>
	 *
	 * @param input 参数值
	 * @return 不会返回Null，如果不存在数据则返回emptySet
	 * @see #splitToLongSet(CharSequence, char)
	 */
	public static @Nonnull Set<Long> splitToLongSet(CharSequence input) {
		return splitToSet(input, DELIMITER_COMMA, (str) -> Longs.tryParse(str));
	}

//	WEB编程中，经常有将字符串参数转换为集合的场景，底层是基于Guava的Splitter。
//
//	返回Set，主要是为了去重，要传递给其他方法时，可用Collection来接收参数。
//
//	如果字符串参数为null或empty时，返回空Set；拆分参数时，会忽略空字符串，也会返回值为null的元素
//	public void addXXXX(String param){
//		//默认以英文逗号为分隔符，这个返回集合：long[1001,1002]，会忽略空字符串和无法转换为数字的值
//		Set<Long> ids=ParamUtil.splitToLongSet(",1001,1002");
//		//显式传递分隔符，分隔符仅支持char类型，这个返回集合：long[1000,1001]，会忽略空字符串和无法转换为数字的值
//		Set<Long> ids=ParamUtil.splitToLongSet("1000|1001|word1002",'|');
//		//也可以返回其他类型，通过函数映射返回的值
//		//默认以英文逗号分隔，这个返回集合：String["穷则变","变则通","通则久"]
//		Set<String> words=splitToSet("穷则变,变则通,通则久",String::valueOf);
//		//显式指定分隔符，这个返回集合：String["穷则变","变则通","通则久"]
//		Set<String> words=splitToSet("穷则变|变则通|通则久",'|',String::valueOf);
//		//转换为Set<Integer>，过滤掉不能转为int的元素，这个返回集合：int[1001,1002]
//		Set<Integer> words=splitToSet("1001,10003words,1002",(str) -> Ints.tryParse(str));
//	}
}
